/**
 * @license
 *
 * Copyright 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Map Label.
 *
 * @author Luke Mahe (lukem@google.com),
 *         Chris Broadfoot (cbro@google.com)
 */

/**
 * Creates a new Map Label
 * @constructor
 * @extends google.maps.OverlayView
 * @param {Object.<string, *>=} opt_options Optional properties to set.
 */
function MapLabel(opt_options) {
	this.set('fontFamily', 'sans-serif');
	this.set('fontSize', 12);
	this.set('fontColor', '#000000');
	this.set('strokeWeight', 4);
	this.set('strokeColor', '#ffffff');
	this.set('align', 'center');

	this.set('zIndex', 1e3);

	this.setValues(opt_options);
}

MapLabel.prototype = new google.maps.OverlayView;

window['MapLabel'] = MapLabel;

/** @inheritDoc */
MapLabel.prototype.changed = function(prop) {
	switch (prop) {
		case 'fontFamily':
		case 'fontSize':
		case 'fontColor':
		case 'strokeWeight':
		case 'strokeColor':
		case 'align':
		case 'text':
			return this.drawCanvas_();
		case 'maxZoom':
		case 'minZoom':
		case 'position':
			return this.draw();
	}
};

/**
 * Draws the label to the canvas 2d context.
 * @private
 */
MapLabel.prototype.drawCanvas_ = function() {
	var canvas = this.canvas_;
	if (!canvas)
		return;

	var style = canvas.style;
	style.zIndex = /** @type number */(this.get('zIndex'));

	var ctx = canvas.getContext('2d');
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	ctx.strokeStyle = this.get('strokeColor');
	ctx.fillStyle = this.get('fontColor');
	ctx.font = this.get('fontSize') + 'px ' + this.get('fontFamily');

	var strokeWeight = Number(this.get('strokeWeight'));

	var text = this.get('text');
	if (text) {
		var detail = [];
		if (text.indexOf('@') > -1) {
			detail = text.split('@');
			text = detail[0];
		}
		if (strokeWeight) {
			ctx.lineWidth = strokeWeight;
			ctx.strokeText(text, strokeWeight, strokeWeight);
			if (detail.length > 1) {
				var i = 0;
				for (var textval in detail) {
					if (i != 0) {
						ctx.strokeText(detail[textval], strokeWeight, strokeWeight + (16*i));
					}
					i++;
				}
			}
		}

		ctx.fillText(text, strokeWeight, strokeWeight);
		if (detail.length > 1) {
			var j = 0;
			for (var textval in detail) {
				if (j != 0) {
					ctx.fillText(detail[textval], strokeWeight, strokeWeight + (16*j));
				}
				j++;
			}
		}
		var textMeasure = ctx.measureText(text);
		var textWidth = textMeasure.width + strokeWeight;
		style.marginLeft = this.getMarginLeft_(textWidth) + 'px';
		// Bring actual text top in line with desired latitude.
		// Cheaper than calculating height of text.
		style.marginTop = '-0.4em';
	}
};

/**
 * @inheritDoc
 */
MapLabel.prototype.onAdd = function() {
	var canvas = this.canvas_ = document.createElement('canvas');
	var style = canvas.style;
	style.position = 'absolute';

	var ctx = canvas.getContext('2d');
	ctx.lineJoin = 'round';
	ctx.textBaseline = 'top';

	this.drawCanvas_();

	var panes = this.getPanes();
	if (panes) {
		panes.mapPane.appendChild(canvas);
	}
};
MapLabel.prototype['onAdd'] = MapLabel.prototype.onAdd;

/**
 * Gets the appropriate margin-left for the canvas.
 * @private
 * @param {number} textWidth  the width of the text, in pixels.
 * @return {number} the margin-left, in pixels.
 */
MapLabel.prototype.getMarginLeft_ = function(textWidth) {
	switch (this.get('align')) {
		case 'left':
			return 0;
		case 'right':
			return -textWidth;
	}
	return textWidth / -2;
};

/**
 * @inheritDoc
 */
MapLabel.prototype.draw = function() {
	var projection = this.getProjection();

	if (!projection) {
		// The map projection is not ready yet so do nothing
		return;
	}

	if (!this.canvas_) {
		// onAdd has not been called yet.
		return;
	}

	var latLng = /** @type {google.maps.LatLng} */(this.get('position'));
	if (!latLng) {
		return;
	}
	var pos = projection.fromLatLngToDivPixel(latLng);

	var style = this.canvas_.style;

	style['top'] = pos.y + 'px';
	style['left'] = pos.x + 'px';

	style['visibility'] = this.getVisible_();
};
MapLabel.prototype['draw'] = MapLabel.prototype.draw;

/**
 * Get the visibility of the label.
 * @private
 * @return {string} blank string if visible, 'hidden' if invisible.
 */
MapLabel.prototype.getVisible_ = function() {
	var minZoom = /** @type number */(this.get('minZoom'));
	var maxZoom = /** @type number */(this.get('maxZoom'));

	if (minZoom === undefined && maxZoom === undefined) {
		return '';
	}

	var map = this.getMap();
	if (!map) {
		return '';
	}

	var mapZoom = map.getZoom();
	if (mapZoom < minZoom || mapZoom > maxZoom) {
		return 'hidden';
	}
	return '';
};

/**
 * @inheritDoc
 */
MapLabel.prototype.onRemove = function() {
	var canvas = this.canvas_;
	if (canvas && canvas.parentNode) {
		canvas.parentNode.removeChild(canvas);
	}
};
MapLabel.prototype['onRemove'] = MapLabel.prototype.onRemove;
